Add a `stdin` option to ShellCommandAgent

Akinori MUSHA 9 years ago
parent
commit
c3fb669010
2 changed files with 33 additions and 10 deletions
  1. 18 4
      app/models/agents/shell_command_agent.rb
  2. 15 6
      spec/models/agents/shell_command_agent_spec.rb

+ 18 - 4
app/models/agents/shell_command_agent.rb

@@ -11,7 +11,7 @@ module Agents
11 11
     description <<-MD
12 12
       The Shell Command Agent will execute commands on your local system, returning the output.
13 13
 
14
-      `command` specifies the command (either a shell command line string or an array of command line arguments) to be executed, and `path` will tell ShellCommandAgent in what directory to run this command.
14
+      `command` specifies the command (either a shell command line string or an array of command line arguments) to be executed, and `path` will tell ShellCommandAgent in what directory to run this command.  The content of `stdin` will be fed to the command via the standard input.
15 15
 
16 16
       `expected_update_period_in_days` is used to determine if the Agent is working.
17 17
 
@@ -50,6 +50,12 @@ module Agents
50 50
         errors.add(:base, "The path, command, and expected_update_period_in_days fields are all required.")
51 51
       end
52 52
 
53
+      case options['stdin']
54
+      when String, nil
55
+      else
56
+        errors.add(:base, "stdin must be a string.")
57
+      end
58
+
53 59
       unless Array(options['command']).all? { |o| o.is_a?(String) }
54 60
         errors.add(:base, "command must be a shell command line string or an array of command line arguments.")
55 61
       end
@@ -79,8 +85,9 @@ module Agents
79 85
       if Agents::ShellCommandAgent.should_run?
80 86
         command = opts['command']
81 87
         path = opts['path']
88
+        stdin = opts['stdin']
82 89
 
83
-        result, errors, exit_status = run_command(path, command)
90
+        result, errors, exit_status = run_command(path, command, stdin)
84 91
 
85 92
         vals = {"command" => command, "path" => path, "exit_status" => exit_status, "errors" => errors, "output" => result}
86 93
         created_event = create_event :payload => vals
@@ -91,15 +98,22 @@ module Agents
91 98
       end
92 99
     end
93 100
 
94
-    def run_command(path, command)
101
+    def run_command(path, command, stdin)
95 102
       begin
96 103
         rout, wout = IO.pipe
97 104
         rerr, werr = IO.pipe
105
+        rin,  win = IO.pipe
98 106
 
99
-        pid = spawn(*command, chdir: path, out: wout, err: werr)
107
+        pid = spawn(*command, chdir: path, out: wout, err: werr, in: rin)
100 108
 
101 109
         wout.close
102 110
         werr.close
111
+        rin.close
112
+
113
+        if stdin
114
+          win.write stdin
115
+          win.close
116
+        end
103 117
 
104 118
         (result = rout.read).strip!
105 119
         (errors = rerr.read).strip!

+ 15 - 6
spec/models/agents/shell_command_agent_spec.rb

@@ -12,7 +12,8 @@ describe Agents::ShellCommandAgent do
12 12
 
13 13
     @valid_params2 = {
14 14
       path: @valid_path,
15
-      command: [RbConfig.ruby, '-e', 'puts "hello, world."; STDERR.puts "warning!"'],
15
+      command: [RbConfig.ruby, '-e', 'puts "hello, #{STDIN.eof? ? "world" : STDIN.read.strip}."; STDERR.puts "warning!"'],
16
+      stdin: "{{name}}",
16 17
       expected_update_period_in_days: '1',
17 18
     }
18 19
 
@@ -27,7 +28,8 @@ describe Agents::ShellCommandAgent do
27 28
     @event = Event.new
28 29
     @event.agent = agents(:jane_weather_agent)
29 30
     @event.payload = {
30
-      :cmd => "ls"
31
+      'name' => 'Huginn',
32
+      'cmd' => 'ls',
31 33
     }
32 34
     @event.save!
33 35
 
@@ -58,7 +60,7 @@ describe Agents::ShellCommandAgent do
58 60
 
59 61
   describe "#working?" do
60 62
     it "generating events as scheduled" do
61
-      stub(@checker).run_command(@valid_path, 'pwd') { ["fake pwd output", "", 0] }
63
+      stub(@checker).run_command(@valid_path, 'pwd', nil) { ["fake pwd output", "", 0] }
62 64
 
63 65
       expect(@checker).not_to be_working
64 66
       @checker.check
@@ -71,7 +73,7 @@ describe Agents::ShellCommandAgent do
71 73
 
72 74
   describe "#check" do
73 75
     before do
74
-      stub(@checker).run_command(@valid_path, 'pwd') { ["fake pwd output", "", 0] }
76
+      stub(@checker).run_command(@valid_path, 'pwd', nil) { ["fake pwd output", "", 0] }
75 77
     end
76 78
 
77 79
     it "should create an event when checking" do
@@ -84,7 +86,7 @@ describe Agents::ShellCommandAgent do
84 86
     it "should create an event when checking (unstubbed)" do
85 87
       expect { @checker2.check }.to change { Event.count }.by(1)
86 88
       expect(Event.last.payload[:path]).to eq(@valid_path)
87
-      expect(Event.last.payload[:command]).to eq([RbConfig.ruby, '-e', 'puts "hello, world."; STDERR.puts "warning!"'])
89
+      expect(Event.last.payload[:command]).to eq([RbConfig.ruby, '-e', 'puts "hello, #{STDIN.eof? ? "world" : STDIN.read.strip}."; STDERR.puts "warning!"'])
88 90
       expect(Event.last.payload[:output]).to eq('hello, world.')
89 91
       expect(Event.last.payload[:errors]).to eq('warning!')
90 92
     end
@@ -97,7 +99,7 @@ describe Agents::ShellCommandAgent do
97 99
 
98 100
   describe "#receive" do
99 101
     before do
100
-      stub(@checker).run_command(@valid_path, @event.payload[:cmd]) { ["fake ls output", "", 0] }
102
+      stub(@checker).run_command(@valid_path, @event.payload[:cmd], nil) { ["fake ls output", "", 0] }
101 103
     end
102 104
 
103 105
     it "creates events" do
@@ -108,6 +110,13 @@ describe Agents::ShellCommandAgent do
108 110
       expect(Event.last.payload[:output]).to eq("fake ls output")
109 111
     end
110 112
 
113
+    it "creates events (unstubbed)" do
114
+      @checker2.receive([@event])
115
+      expect(Event.last.payload[:path]).to eq(@valid_path)
116
+      expect(Event.last.payload[:output]).to eq('hello, Huginn.')
117
+      expect(Event.last.payload[:errors]).to eq('warning!')
118
+    end
119
+
111 120
     it "does not run when should_run? is false" do
112 121
       stub(Agents::ShellCommandAgent).should_run? { false }
113 122